package monash.med.crystallography.DatasetTools.FileJoiner;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

/**
 * FileJoiner by Steve Androulakis - Joins files together that were split using FileSplitter
 * <p>
 * Use static method joinFile(firstFile[, outputDir]) where
 * firstFile is the first file of the set (eg. splitfile.tar.bz.0)
 * and outputDir is an optional parameter for where the joined file
 * will be placed.
 * 
 * @author Steve Androulakis (Monash University)
 * @version 1.0
 */
public class FileJoiner
{
	/**
	 * @param	firstFile is the first file of the set (eg. splitfile.tar.bz.0)
	 */
	public static String joinFile(String firstFile)
	{
		return join(firstFile, new File(firstFile).getParent());
	}	

	/**
	 * @param	 firstFile	 is the first file of the set (eg. splitfile.tar.bz.0)
	 * @param	outputDir	 is an optional parameter for where the joined file
	 * will be placed.
	 */
	public static String joinFile(String firstFile, String outputDir)
	{
		return join(firstFile, outputDir);
	}

	private static String join(String firstFile, String outputDir)
	{
		String returnFile = "";
		
		try
		{
			File file = new File(firstFile);
			String path = new File(outputDir).getPath();
			String fileWithoutExt = file.getName().substring(0, file.getName().lastIndexOf("."));
			
			new File(path + File.separator + file.getName() + File.separator).mkdir();
			File fileWrite = new File(path + File.separator + fileWithoutExt);
			returnFile = fileWrite.getAbsolutePath();
			if (fileWrite.exists())
			{
				throw new IOException("File " + file.getName() + " already exists. Exiting");
			}
			File firstPart = new File(file.getAbsolutePath());
			if (!firstPart.exists())
			{
				throw new FileNotFoundException(firstPart.getAbsolutePath() + " not found. Exiting");
			}
			
			for (int i = 0; new File(file.getParent() + File.separator + fileWithoutExt + "." + i).exists(); i++)
			{
				File fileRead = new File(file.getParent() + File.separator + fileWithoutExt + "." + i);
				System.out.println("Joining " + fileRead.getName());
				System.out.println("Size (bytes) " + fileRead.length());
				FileInputStream fileInputStreamPiece = new FileInputStream(fileRead);
				FileChannel finc = fileInputStreamPiece.getChannel();
				MappedByteBuffer mbb = finc.map(FileChannel.MapMode.READ_ONLY, 0, fileRead.length());
				
				FileOutputStream fileOutputStreamPieces = new FileOutputStream(fileWrite, true);
				FileChannel fout = fileOutputStreamPieces.getChannel();
				fout.write(mbb);
                                
                                finc.close();
				fout.close();
			}
			System.out.println("Finished Joining: " + returnFile);
		}
		catch (FileNotFoundException e)
		{
			System.out.println(e.getMessage());
		}
		catch (IOException e)
		{
			System.out.println(e.getMessage());
                        e.printStackTrace();
			System.out.println("ERROR: Failed or interrupted file operation");
		}

		return returnFile;
	}

	/**
	 * The commandline implementaton of the {@link FileJoiner} class.
	 * <p>
	 * Run <i>java -jar FileJoiner.jar</i> for instructions on usage.
	 */
	public static void main(String[] args)
	{
		// TODO Auto-generated method stub
		if (args.length == 1)
		{
			FileJoiner.joinFile(args[0]);
		}
		else if (args.length == 2)
		{
			FileJoiner.joinFile(args[0], args[1]);
		}		
		else
		{
			System.out.println("FileJoiner by Steve Androulakis - For joining split files using FileSplitter");
			System.out.println("");
			System.out.println("USAGE:");
			System.out.println("FileJoiner <firstFile> <destDir>");
			System.out.println("");
			System.out.println("firstFile: The path to the first file in the split set");
			System.out.println("destDir (optional): The path the joined file will be output to");
			System.out
					.println("Example - /Users/John/Desktop/mydataset.tar.0 will find all the parts starting with that filename and join");
			System.out.println("(mydataset.tar.0, mydataset.tar.1 etc.)");
		}
	}
}